home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 July: Mac OS SDK / Dev.CD Jul 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-25  |  22.2 KB  |  664 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. /*
  14.     Notes to developers:
  15.     
  16.     1. The WatchDog functionality is *NOT* needed in your drivers.  It is part of an experiment to determine
  17.     if IntReads are ever dropped on the floor.  It was left in (but disabled) and checked into the 
  18.     projector database so that the coding effort wasn't lost.  We do not believe that IntReads are lost, so
  19.     your drivers should not need this WatchDog functionality.
  20.     
  21.     2. Apple reserves the right to do the following:
  22.         Release Mouse or Keyboard drivers that are vendor specific for Apple products
  23.         Release said mouse or keyboard drivers in binary form (but not necessarily in source form)
  24.         Prevent 3rd parties from writing generic drivers
  25.  
  26. */
  27.  
  28.  
  29. #include <DriverServices.h>
  30. #include <Devices.h>
  31. #include <LowMem.h>
  32. #include <MacTypes.h>
  33. #include <Processes.h>
  34. #include <USB.h>
  35.  
  36. #include "MouseModule.h"
  37.  
  38. enum{
  39.     kCheckEvery = 10000,
  40.     kFastCheck = 1000
  41.     };
  42.  
  43. #define    EnableWatchDog    0
  44. #define EnableRemoteWakeup 0
  45.  
  46. usbMousePBStruct myMousePB;
  47. usbMousePBStruct watchDogPB;
  48.  
  49. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  50. {
  51.     paramblock->usbReference = theInterfaceRef;
  52.     paramblock->pbVersion = kUSBCurrentPBVersion;
  53.     
  54.     paramblock->usb.cntl.WIndex = 0;             
  55.     paramblock->usb.cntl.WValue = 0;
  56.     
  57.     paramblock->usbBuffer = nil;        
  58.     paramblock->usbActCount = 0;
  59.     paramblock->usbReqCount = 0;
  60.     paramblock->usbFlags = 0;
  61.     paramblock->usbOther = 0;
  62.     
  63.     paramblock->usbStatus = noErr;
  64. }
  65.  
  66.  
  67.  
  68. Boolean immediateError(OSStatus err)
  69. {
  70.     return((err != kUSBPending) && (err != noErr) );
  71. }
  72.  
  73. void MouseInitiateTransaction(USBPB *pb)
  74. {
  75. usbMousePBStruct *pMousePB;
  76. OSStatus myErr;
  77.  
  78.     pMousePB = (usbMousePBStruct *)(pb);
  79.     pMousePB->transDepth++;
  80.     if (pMousePB->transDepth < 0)
  81.     {
  82.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  83.     }
  84.     
  85.     if (pMousePB->transDepth > 1)
  86.     {
  87.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  88.     }
  89.     
  90.     if (pMousePB->driverRemovalPending)
  91.     {
  92.         pMousePB->pb.usbRefcon = kReturnFromDriver;
  93.         return;
  94.     }
  95.  
  96.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  97.     {
  98.         case kConfigureInterface:
  99.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  100.             
  101.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  102.             pMousePB->pb.usbRefcon |= kCompletionPending;
  103.             
  104.             myErr = USBConfigureInterface( &pMousePB->pb );
  105.             if(immediateError(myErr))
  106.             {
  107.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr);
  108.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  109.             }
  110.             break;
  111.         
  112.         case kSetProtocol:
  113.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  114.             
  115.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  116.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  117.             pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  118.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  119.             
  120.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  121.             pMousePB->pb.usbRefcon |= kCompletionPending;
  122.         
  123.             myErr = USBDeviceRequest(&pMousePB->pb);
  124.             if (immediateError(myErr))
  125.             {
  126.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr);
  127.             }
  128.             break;
  129.             
  130.         case kSetIdleRequest:
  131.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a SetIdle on non-Apple mice, as some 3rd party mice don't send reports on button up", pMousePB->pipeRef);
  132.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  133.             
  134.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  135.             
  136.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  137.             pMousePB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  138.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  139.             
  140.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  141.             pMousePB->pb.usbRefcon |= kCompletionPending;
  142.  
  143.             myErr = USBDeviceRequest(&pMousePB->pb);
  144.             if(immediateError(myErr))
  145.             {
  146.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr);
  147.             }
  148.             break;
  149.  
  150. #if EnableRemoteWakeup
  151.         case kSetRemoteWakeup:
  152.             USBExpertStatusLevel(3, pMousePB->interfaceRef, kMouseModuleName": Set remote wakeup for mouse", pMousePB->pipeRef);
  153.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  154.             
  155.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);            
  156.             
  157.             pMousePB->pb.usb.cntl.BRequest = kUSBRqSetFeature;
  158.             pMousePB->pb.usb.cntl.WValue = kUSBFeatureDeviceRemoteWakeup; 
  159.             pMousePB->pb.usb.cntl.WIndex = 0;
  160.             
  161.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  162.             pMousePB->pb.usbRefcon |= kCompletionPending;
  163.  
  164.             myErr = USBDeviceRequest(&pMousePB->pb);
  165.             if(immediateError(myErr))
  166.             {
  167.                 USBExpertFatalError(pMousePB->interfaceRef, myErr, kMouseModuleName": set remote wakeup request - immediate error", myErr);
  168.             }
  169.             break;
  170. #endif
  171.  
  172.         case kFindPipe:
  173.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  174.             
  175.             pMousePB->pb.usbFlags = kUSBIn;
  176.             pMousePB->pb.usbClassType = kUSBInterrupt;
  177.             
  178.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  179.             pMousePB->pb.usbRefcon |= kCompletionPending;
  180.         
  181.             myErr = USBFindNextPipe( &pMousePB->pb );
  182.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  183.             {
  184.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr);
  185.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  186.             }
  187.             
  188.             break;
  189.         
  190.         case kReadInterruptPipe:
  191.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  192.  
  193.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  194.             pMousePB->pb.usbReqCount = pMousePB->maxPacketSize;
  195.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  196.             
  197.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  198.             pMousePB->pb.usbRefcon |= kCompletionPending;
  199.             #ifndef DDKBuild
  200.             pMousePB->pb.usbFlags |= kUSBDebugAwareFlag;
  201.             #endif
  202.         
  203.             myErr = USBIntRead(&pMousePB->pb);
  204.             if(immediateError(myErr))
  205.             {
  206.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr);
  207.             }
  208.             break;
  209.             
  210.         case kResetMouse:
  211.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  212.             
  213.             pMousePB->pb.usbRefcon |= kCompletionPending;
  214.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  215.  
  216.             myErr = USBResetDevice( &pMousePB->pb );
  217.             
  218.             if(myErr == kUSBDeviceBusy)
  219.             {
  220.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": reset busy, backing off", myErr);
  221.                 pMousePB->pb.usbReqCount = 100;
  222.                 pMousePB->pb.usbRefcon = kResetMouseDelay | kCompletionPending;
  223.                 USBDelay(  &pMousePB->pb );
  224.             }
  225.             else if(immediateError(myErr))
  226.             {
  227.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kResetMouse - immediate error", myErr);
  228.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  229.             }
  230.             break;
  231.  
  232.         case kGetPortStatus:
  233.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  234.             pMousePB->pb.usbRefcon |= kCompletionPending;
  235.             myErr = USBPortStatus(  &pMousePB->pb );
  236.             if(myErr == kUSBDeviceBusy)
  237.             {
  238.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": status busy, backing off", myErr);
  239.                 pMousePB->pb.usbReqCount = 100;
  240.                 pMousePB->pb.usbRefcon = kPortStatusDelay | kCompletionPending;
  241.                 USBDelay(  &pMousePB->pb );
  242.             }
  243.             else if(immediateError(myErr))
  244.             {
  245.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kGetPortStatus - immediate error", myErr);
  246.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  247.             }
  248.             break;
  249.  
  250.         default:
  251.             USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  252.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  253.             break;
  254.     }
  255.     
  256. // At this point the control is returned to the system.  If a USB transaction
  257. // has been initiated, then it will call the Complete procs
  258. // (below) to handle the results of the transaction.
  259. }
  260.  
  261. void WatchDogCompletionProc(USBPB *pb)
  262. {
  263. usbMousePBStruct *pWatchDogPB;
  264. OSStatus myErr;
  265. UInt32    delayTime = 0;
  266.  
  267.     pWatchDogPB = (usbMousePBStruct *)(pb);
  268.     if (!pWatchDogPB->driverRemovalPending)
  269.     {
  270.         delayTime = 50;        // come back in 50ms if we're currently processing a completion callback
  271.         if (myMousePB.pb.usbRefcon & kCompletionInProgess)
  272.         {
  273.             USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog occurred while processing a completion callback (check again in 50ms)", myMousePB.pb.usbRefcon);
  274.         }
  275.         else
  276.         {
  277.             switch(pWatchDogPB->watchDogState)
  278.             {
  279.                 case kDelay10Seconds:
  280.                     
  281.                     if (pWatchDogPB->watchDogActivityFlag)
  282.                     {
  283.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Mouse activity detected", pWatchDogPB->watchDogState);
  284.                         delayTime = kCheckEvery;
  285.                         pWatchDogPB->watchDogAbortFlag = false;
  286.                     }
  287.                     else
  288.                     {
  289.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No mouse activity detected, aborting pipe", pWatchDogPB->watchDogState);
  290.                         delayTime = kFastCheck;
  291.                         pWatchDogPB->watchDogState = kCheckForAbort;
  292.                     }
  293.                     break;
  294.         
  295.                 case kCheckForAbort:
  296.                     delayTime = kCheckEvery;
  297.                     pWatchDogPB->watchDogState = kDelay10Seconds;
  298.                     
  299.                     if (pWatchDogPB->watchDogAbortFlag)
  300.                     {
  301.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Abort detected in completion routine", pWatchDogPB->watchDogState);
  302.                     }
  303.                     else
  304.                     {
  305.                         USBExpertStatusLevel(4, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No abort detected, restarting int read", pWatchDogPB->watchDogState);
  306.                         InitParamBlock(myMousePB.pipeRef, &myMousePB.pb);
  307.             
  308.                         myMousePB.pb.usbBuffer = (Ptr)myMousePB.hidReport;
  309.                         myMousePB.pb.usbReqCount = myMousePB.maxPacketSize;
  310.                         myMousePB.pb.usb.cntl.WIndex = myMousePB.interfaceDescriptor.interfaceNumber;    
  311.                         
  312.                         myMousePB.pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  313.                         myMousePB.pb.usbRefcon = kReadInterruptPipe + kCompletionPending;
  314.                         #ifndef DDKBuild
  315.                         myMousePB.pb.usbFlags |= kUSBDebugAwareFlag;
  316.                         #endif
  317.                     
  318.                         myErr = USBIntRead(&myMousePB.pb);
  319.                         if(immediateError(myErr))
  320.                         {
  321.                             USBExpertFatalError(myMousePB.interfaceRef, kUSBInternalErr, kMouseModuleName": Watchdog - Read Interrupt Pipe (ImmediateError)", myErr);
  322.                         }
  323.                     }
  324.                     pWatchDogPB->watchDogAbortFlag = false;
  325.                     break;
  326.                     
  327.             }
  328.             pWatchDogPB->watchDogActivityFlag = false;
  329.             pWatchDogPB->watchDogAbortFlag = false;
  330.             if (pWatchDogPB->watchDogState == kCheckForAbort)
  331.             {
  332.                 USBAbortPipeByReference(pWatchDogPB->pipeRef);
  333.             }
  334.         }
  335.         InitParamBlock( pWatchDogPB->interfaceRef, &pWatchDogPB->pb );
  336.         
  337.         pWatchDogPB->pb.usbBuffer = 0;
  338.         pWatchDogPB->pb.usbActCount = 0;
  339.         pWatchDogPB->pb.usbReqCount = delayTime;            
  340.         
  341.         pWatchDogPB->pb.usbRefcon = 0;
  342.         pWatchDogPB->pb.usbCompletion = (USBCompletion)WatchDogCompletionProc;
  343.         
  344.         USBDelay(&pWatchDogPB->pb);
  345.         
  346.     }
  347.     return;
  348. }
  349.  
  350.  
  351. void MouseCompletionProc(USBPB *pb)
  352. {
  353. usbMousePBStruct     *pMousePB;
  354. unsigned char        * errstring;
  355. USBPipeState         pipeState;
  356.  
  357. #if EnableWatchDog
  358. OSStatus            myErr;
  359. #endif
  360.  
  361.     pMousePB = (usbMousePBStruct *)(pb);
  362.     pMousePB->transDepth--;
  363.     if (pMousePB->transDepth < 0)
  364.     {
  365.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  366.     }
  367.     
  368.     if (pMousePB->transDepth > 1)
  369.     {
  370.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  371.     }
  372.     
  373.     pMousePB->pb.usbRefcon |= kCompletionInProgess;                                            // make certain the watchdog routine doesn't race us
  374.     
  375.     if( (pMousePB->pb.usbStatus != noErr) && ((pMousePB->pb.usbRefcon & kStageMask) != kGetPortStatus) )        // was there an error?
  376.     {
  377.         switch(pMousePB->pb.usbRefcon & kStageMask)                                            // yes, so show where the error occurred
  378.         {
  379.             case kSetProtocol:                    errstring = kMouseModuleName": Error during kSetProtocol"; break;
  380.             case kSetIdleRequest:                  errstring = kMouseModuleName": Error during kSetIdleRequest"; break;
  381. #if EnableRemoteWakeup
  382.             case kSetRemoteWakeup:              errstring = kMouseModuleName": Error during kSetRemoteWakeup"; break;
  383. #endif
  384.             case kConfigureInterface:            errstring = kMouseModuleName": Error during kConfigureInterface"; break;
  385.             case kFindPipe:                      errstring = kMouseModuleName": Error during kFindPipe"; break;
  386.             case kReadInterruptPipe:
  387.                 {
  388.                 errstring = kMouseModuleName": Error during ReadInterruptPipe";
  389.                 LMSetMouseButtonState(0x80);    // release any possibly held-down mouse button
  390.                 break;
  391.                 }
  392.             default:                              errstring = kMouseModuleName": Error occurred, but state is unknown"; break;
  393.         };
  394.         
  395.         pMousePB->pb.usbRefcon &= (kStageMask + kCompletionInProgess);                        // save the refcon & completion in progress flag
  396.         pMousePB->pb.usbRefcon |= kRetryTransaction;                                        // set up to retry the transaction
  397.         pMousePB->retryCount--;
  398.         
  399.         // don't put out a fatal error message if an expected abort has occurred
  400.         if ((pMousePB->pb.usbStatus != kUSBAbortedError) || (watchDogPB.watchDogState != kCheckForAbort))
  401.         {
  402.             USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & kStageMask));
  403.         }
  404.         
  405.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon & kStageMask) == kSetIdleRequest))
  406.         {
  407.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef);
  408.             pMousePB->pb.usbRefcon = 
  409. #if EnableRemoteWakeup
  410.             kSetRemoteWakeup
  411. #else
  412.             kFindPipe
  413. #endif
  414.             ;
  415.             pMousePB->pb.usbStatus = noErr;
  416.         }
  417.         else
  418.         {
  419.             if ((pMousePB->pb.usbStatus == kUSBAbortedError) && (watchDogPB.watchDogState == kCheckForAbort))
  420.             {
  421.                 USBExpertStatusLevel(5, pMousePB->interfaceRef, kMouseModuleName": Expected abort has occurred - retry int read", pMousePB->interfaceRef);
  422.                 if (pMousePB->pipeRef)
  423.                 {    
  424.                         watchDogPB.watchDogAbortFlag = true;                                // flag that we had the abort
  425.                 }
  426.                 USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                    // yes, so what it's state?
  427.                 if (pipeState != kUSBActive)                                                // if it's not active, try to clear it.  It might be stalled...
  428.                 {
  429.                     USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  430.                     USBClearPipeStallByReference(pMousePB->pipeRef);
  431.                 }
  432.             }
  433.             else if ((!pMousePB->retryCount) || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  434.             {                                                                                // or received an abort?
  435.                 USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef);
  436.                 pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess;            // if so, just exit.
  437.                 pMousePB->intPipeAborted = true;    
  438.             }
  439.             else                                                                            // if it didn't abort and there's retries left, then...
  440.             {
  441.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  442.                 {
  443.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  444.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  445.                     {
  446.                         USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  447.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  448.                     }
  449.                 }
  450.                 if( (pMousePB->pb.usbStatus == kUSBNotRespondingErr)  ) 
  451.                 {
  452.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": doing port status", pMousePB->interfaceRef);
  453.                     pMousePB->previousState = pMousePB->pb.usbRefcon;
  454.                     pMousePB->pb.usbRefcon = kGetPortStatus;
  455.                 }
  456.             }
  457.         }
  458.     }
  459.     else
  460.     {
  461.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  462.         pMousePB->retryCount = kMouseRetryCount;
  463.     }
  464.  
  465.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  466.     {                                                
  467.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  468.         switch(pMousePB->pb.usbRefcon & kStageMask)
  469.         {
  470.             case kConfigureInterface:
  471.                 pMousePB->pb.usbRefcon = kSetProtocol + kCompletionInProgess;
  472.                 break;
  473.                 
  474.             case kSetProtocol:
  475.                 if (kVendorID_AppleComputer == USBToHostWord(pMousePB->deviceDescriptor.vendor) )
  476.                 {
  477.                     pMousePB->pb.usbRefcon = 
  478. #if EnableRemoteWakeup
  479.                     kSetRemoteWakeup
  480. #else
  481.                     kFindPipe
  482. #endif
  483.                     + kCompletionInProgess;
  484.                 }
  485.                 else
  486.                 {
  487.                     pMousePB->pb.usbRefcon = kSetIdleRequest + kCompletionInProgess;
  488.                 }
  489.                 break;
  490.                 
  491.             case kSetIdleRequest:
  492.                 pMousePB->pb.usbRefcon = 
  493. #if EnableRemoteWakeup
  494.             kSetRemoteWakeup
  495. #else 
  496.             kFindPipe
  497. #endif
  498.                 + kCompletionInProgess;
  499.                 break;
  500.                 
  501. #if EnableRemoteWakeup
  502.             case kSetRemoteWakeup:
  503.                 pMousePB->pb.usbRefcon = kFindPipe;
  504.                 break;
  505. #endif
  506.                 
  507.             case kFindPipe:
  508.                 pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue;
  509.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  510.                 pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess;
  511.  
  512.                 USBExpertStatus( watchDogPB.interfaceRef, kMouseModuleName": Initialize watchdog", 0);
  513.                 InitParamBlock( watchDogPB.interfaceRef, &watchDogPB.pb );
  514.                 
  515.                 watchDogPB.pipeRef = pMousePB->pipeRef;
  516.                 watchDogPB.watchDogState = kDelay10Seconds;
  517.                 
  518.                 watchDogPB.pb.usbBuffer = 0;
  519.                 watchDogPB.pb.usbActCount = 0;
  520.                 watchDogPB.pb.usbReqCount = 20000;            // check for mouse activity every twenty seconds
  521.                 watchDogPB.watchDogActivityFlag = false;
  522.                 
  523.                 watchDogPB.pb.usbRefcon =  0;
  524.                 watchDogPB.pb.usbCompletion = (USBCompletion)WatchDogCompletionProc;
  525.                 
  526.                 
  527. #if EnableWatchDog
  528.                 myErr = USBDelay(&watchDogPB.pb);
  529.                 if(immediateError(myErr))
  530.                 {
  531.                     USBExpertFatalError(pb->usbReference, myErr, kMouseModuleName": Setting up watchdog - USBDelay immediate error", 0);
  532.                 }
  533. #endif
  534.  
  535.                 break;
  536.                 
  537.             case kReadInterruptPipe:
  538.                 watchDogPB.watchDogActivityFlag = true;
  539.                 if (myMousePB.pNotificationRoutine)
  540.                 {
  541.                     (*myMousePB.pNotificationRoutine)(myMousePB.notificationRefcon, pMousePB->pb.usbActCount, (void *)pMousePB->hidReport, myMousePB.interfaceRef);
  542.                 }
  543.                 pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess;
  544.                 break;
  545.  
  546.             case kPortStatusDelay:
  547.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef);
  548.                     pMousePB->pb.usbRefcon = kGetPortStatus;
  549.                 break;
  550.  
  551.             case kResetMouseDelay:
  552.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef);
  553.                     pMousePB->pb.usbRefcon = kResetMouse;
  554.                 break;
  555.  
  556.             case kResetMouse:
  557.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": mouse now reset", pMousePB->interfaceRef);
  558.                     // Just give up here, the composite driver should now take care of things.
  559.                 break;
  560.  
  561.             case kGetPortStatus:
  562.                 if(pb->usbStatus == kUSBDeviceDisconnected)
  563.                 {
  564.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives device disconnected, exiting", pMousePB->interfaceRef);
  565.                     pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess;            // if so, just exit.
  566.                 }
  567.                 else if(pb->usbStatus == kUSBPortDisabled)
  568.                 {
  569.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives port disabled, resetting", pMousePB->interfaceRef);
  570.                     pMousePB->pb.usbRefcon = kResetMouse;
  571.                 }
  572.                 else if(pb->usbStatus == noErr)
  573.                 {
  574.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status transient error, restarting", pMousePB->interfaceRef);
  575.                     //pMousePB->retryCount = kMouseRetryCount;    --> done automatically
  576.  
  577.                     pMousePB->pb.usbRefcon = pMousePB->previousState;
  578.                 }
  579.                 else
  580.                 {
  581.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status unknown error", pb->usbStatus);
  582.                 }
  583.             
  584.                 break;
  585.  
  586.             default:
  587.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon );
  588.                 pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver + kCompletionInProgess;
  589.                 break;
  590.         }
  591.     }
  592.     
  593.     pMousePB->pb.usbRefcon &= ~(kCompletionInProgess);
  594.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending))
  595.         MouseInitiateTransaction(pb);
  596. }
  597.  
  598.  
  599. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  600. {
  601. #pragma unused (interfacenum)
  602.  
  603. static Boolean beenThereDoneThat = false;
  604.  
  605.     if(beenThereDoneThat)
  606.     {
  607.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0);
  608.         return;
  609.     }
  610.     beenThereDoneThat = true;
  611.     
  612.     // DebugStr("\pIn Mouse Interface Entry routine");
  613.  
  614.     watchDogPB.watchDogState = 0;
  615.     watchDogPB.watchDogAbortFlag = false;
  616.     watchDogPB.watchDogActivityFlag = false;
  617.     watchDogPB.driverRemovalPending = false;
  618.     watchDogPB.interfaceRef = theInterfaceRef;        
  619.     watchDogPB.pipeRef = nil;        
  620.     watchDogPB.pb.pbLength = sizeof(usbMousePBStruct);
  621.  
  622.     myMousePB.driverRemovalPending = false;
  623.     myMousePB.intPipeAborted = false;    
  624.  
  625.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  626.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;            
  627.     
  628.     myMousePB.transDepth = 0;                            
  629.     myMousePB.retryCount = kMouseRetryCount;
  630.       
  631.     myMousePB.pSHIMInterruptRoutine = nil;
  632.     myMousePB.pSavedInterruptRoutine = nil;
  633.     
  634.     myMousePB.notificationRefcon = 0;
  635.     myMousePB.pNotificationRoutine = NotifyRegisteredHIDUser;
  636.  
  637.     myMousePB.interfaceRef = theInterfaceRef;        
  638.     myMousePB.pipeRef = nil;        
  639.     
  640.     InitParamBlock(theInterfaceRef, &myMousePB.pb);
  641.     
  642.     myMousePB.pb.usbReference = theInterfaceRef;
  643.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  644.     myMousePB.pb.usbRefcon = kConfigureInterface;        
  645.     
  646.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  647.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  648.     {
  649.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  650.     }
  651.     else
  652.     {
  653.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  654.     }
  655.     
  656.     myMousePB.pCursorDeviceInfo = 0;                
  657.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  658.  
  659.     MouseInitiateTransaction(&myMousePB.pb);
  660. }
  661.  
  662.  
  663.  
  664.